package com.young.coderule.common.scan;

import com.young.coderule.common.annotation.CodeRule;
import com.young.coderule.common.util.AopTargetUtils;
import com.young.coderule.common.util.MyUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RestController;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;


/**
 * @DESCRIPTION: 编码规则资源扫描器
 * @USER: Young
 * @DATE: 2022/7/29 9:29
 */
public class CodeRuleResourceScaner implements BeanPostProcessor {

    @Autowired
    private CodeRuleResourceFactory codeRuleResourceFactory;

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {

        //如果controller是代理对象,则需要获取原始类的信息
        Object aopTarget = AopTargetUtils.getTarget(bean);

        if (aopTarget == null) {
            aopTarget = bean;
        }
        Class<?> clazz = aopTarget.getClass();

        //判断是不是控制器,不是控制器就略过
        boolean controllerFlag = getControllerFlag(clazz);
        if (!controllerFlag) {
            return bean;
        }

        //扫描控制器的所有带CodeRule注解的方法，并映射到资源工厂缓存
         doScan(clazz);

        return bean;
    }


    /**
     * 判断一个类是否是控制器
     */
    private boolean getControllerFlag(Class<?> clazz) {
        Annotation[] annotations = clazz.getAnnotations();

        for (Annotation annotation : annotations) {
            if (RestController.class.equals(annotation.annotationType()) || Controller.class.equals(annotation.annotationType())) {
                return true;
            }
        }
        return false;
    }

    /**
     * 扫描整个类中包含的所有CodeRule，并映射到资源工厂缓存
     */
    private void doScan(Class<?> clazz) {

        Method[] declaredMethods = clazz.getDeclaredMethods();
        if (declaredMethods.length > 0) {
            for (Method declaredMethod : declaredMethods) {

                CodeRule codeRuleAnnotation = declaredMethod.getAnnotation(CodeRule.class);
                if(codeRuleAnnotation==null){
                    continue;
                }
                ResourceDefinition resourceDefinition = MyUtils.getResourceDefinition(codeRuleAnnotation, clazz.getSimpleName());
                this.codeRuleResourceFactory.mapResource(resourceDefinition.getCode(), resourceDefinition);
            }
        }

    }

}
